///////////////////////////////////////////////////////////////////////////////
//
// lighthouse3D - 3D Software Library
//
// File: COBJFileHandler.cpp
//
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2003-2013 Marcus Reinhardt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
///////////////////////////////////////////////////////////////////////////////
//
// You can find a copy of the GNU General Public License (gpl.txt) in the
// directory of the library.
//
///////////////////////////////////////////////////////////////////////////////
#include "COBJFileHandler.h"

///////////////////////////////////////////////////////////////////////////////
// C3DSFileHandler::C3DSFileHandler( ... )
///////////////////////////////////////////////////////////////////////////////
COBJFileHandler::COBJFileHandler()
{
  pMeshStorage = NULL;
}

///////////////////////////////////////////////////////////////////////////////
// COBJFileHandler::~COBJFileHandler( ... )
///////////////////////////////////////////////////////////////////////////////
COBJFileHandler::~COBJFileHandler()
{
}

///////////////////////////////////////////////////////////////////////////////
// COBJFileHandler::scanfacetriple( ... )
///////////////////////////////////////////////////////////////////////////////
void COBJFileHandler::scanFaceTriple(char *s, int *f0, int *f1, int *f2)
{
	int i,c,p;

	char *subs[4];
	char *cstr;
	subs[0] = (char*)malloc(256);
	subs[1] = (char*)malloc(256);
	subs[2] = (char*)malloc(256);
	subs[3] = (char*)malloc(256);

	c = 0;
	p = 0;
	cstr = subs[0];
	for(i=0; i<(int)strlen(s); i++)
	{
		if ( ( s[i] == '/') || ( s[i] == '\\') ){
			c++;
			cstr[p] = '\0';
			cstr = subs[c];
			p=0;
		}
		else{
			cstr[p] = s[i];
			p++;
		}
	}
	cstr[p] = '\0';

	sscanf(subs[0], "%i", f0);
	sscanf(subs[1], "%i", f1);
	sscanf(subs[2], "%i", f2);

	free(subs[0]);
	free(subs[1]);
	free(subs[2]);
}

///////////////////////////////////////////////////////////////////////////////
// COBJFileHandler::loadOBJFile( ... )
///////////////////////////////////////////////////////////////////////////////
bool COBJFileHandler::loadOBJFile(const char *fname, CMeshStorage *storageHandler)
{
  char dummy[10];
  float v1,v2,v3;
  int f1,f2,f3;
  int k,i,j,c;
  char fileLine[256];
  char curFace[128];
  CMeshData *mesh;
  int nr_faces;
  int faces_v[128];
  int loadstep;

  if( storageHandler == NULL )
     return false;

  FILE *f = fopen(fname, "r+t");

  if( f == NULL )
     return false;

  pMeshStorage = storageHandler;

  loadstep = 0;

  while ((fgets(fileLine, 256, f)) != NULL)
  {

	  // Main parsing switch statement
	  switch (fileLine[0])
	  {
		    // Vertex related stuff
			case 'v':

				switch (fileLine[1]) // switch on second char to determine which kind
				{
					// plain vertex
					case ' ': 
						sscanf(fileLine, "%s %f %f %f", dummy, &v1, &v2, &v3);	
						
						if (loadstep == 0)
						{
							if( !pMeshStorage->addNewMesh() )
						    return false;

							mesh = pMeshStorage->getMeshRear();
   							if( mesh == NULL )
								return false;

  						    strcpy(mesh->m_name, "Imported OBJ Model");

							loadstep = 1;
						}


						if( mesh == NULL )
						    return false;
						else
						{
	 					    TMeshVertex vert;

							vert.x = v1;
							vert.y = v2;
							vert.z = v3;

					        mesh->addVert(vert);
						}

						break;

					// texture vertex
					case 't':
						// sscanf(line, "%s %f %f %f", dummy, &(vt->u), &(vt->v), &(vt->w));
						break;
					// vertex normal
					case 'n': 
						break;

				}

				break;

		    // Faces related stuff
			case 'f': 

				if (loadstep == 1)
					loadstep = 0;

				if( mesh == NULL )
				   return false;


				// Begin to parse line
				k=1;
				nr_faces = 0;
				while (k < (int) strlen(fileLine) ) {

					i = k;
					while ( (i < (int)strlen(fileLine) ) && (fileLine[i] == ' ') ) {
						i++;
					}

					j=i;
					c=0;
					while ( (j < (int)strlen(fileLine) ) && (fileLine[j] != ' ') ) {

						if (fileLine[j] != ' ') {
							curFace[c] = fileLine[j];
						}

						j++;
						c++;
					}
					curFace[c] = '\0';

					// Now parse the current Face
					scanFaceTriple(curFace, &f1, &f2, &f3);
					k=j;
				
					faces_v[nr_faces] = f1;
					nr_faces++;
				}

				if (nr_faces == 3) {
					TMeshTriangle face;

					face.v[0] = faces_v[0]-1;
					face.v[1] = faces_v[1]-1;
					face.v[2] = faces_v[2]-1;
					if ( (face.v[0] < mesh->getVertCount()) &&
                         (face.v[1] < mesh->getVertCount()) &&
						 (face.v[2] < mesh->getVertCount()) )
						mesh->addFace(face);
					else
						return false;
				}

				if (nr_faces == 4) {
					TMeshTriangle face;
					face.v[0] = faces_v[2]-1;
					face.v[1] = faces_v[1]-1;
					face.v[2] = faces_v[0]-1;
					if ( (face.v[0] < mesh->getVertCount()) &&
                         (face.v[1] < mesh->getVertCount()) &&
						 (face.v[2] < mesh->getVertCount()) )
					    mesh->addFace(face);
					else
						return false;

					face.v[0] = faces_v[0]-1;
					face.v[1] = faces_v[3]-1;
					face.v[2] = faces_v[2]-1;
					if ( (face.v[0] < mesh->getVertCount()) &&
                         (face.v[1] < mesh->getVertCount()) &&
						 (face.v[2] < mesh->getVertCount()) )
					    mesh->addFace(face);
					else
						return false;
				}

				if (nr_faces > 4) {
					return false;
				}

				break;

		    // Groups related stuff
			case 'g':
				// Here we can extract the object name

				break;
		}
  }

  fclose(f);

  pMeshStorage = NULL;

  return true;
}